#include "ctrl_protocol.h"
#include "ctrl_crc16.h"

#if defined(CTRL_HOST)
#define ctrl_recv_check_src(src)    ((src) == CTRLPROT_SRC_BLE || (src) == CTRLPROT_SRC_DEVICE)
#elif defined(CTRL_DEVICE)
#define ctrl_recv_check_src(src)    ((src) == CTRLPROT_SRC_BLE || (src) == CTRLPROT_SRC_HOST)
#elif defined(CTRL_BLE)
#define ctrl_recv_check_src(src)    ((src) == CTRLPROT_SRC_HOST || (src) == CTRLPROT_SRC_DEVICE)
#else
#define ctrl_recv_check_src(src)    ((src) == CTRLPROT_SRC_BLE || (src) == CTRLPROT_SRC_HOST || (src) == CTRLPROT_SRC_DEVICE)
#endif

static ctrl_prot_t buf[1];

typedef enum { 
    CTRL_RECV_PRE, 
    CTRL_RECV_SRC, 
    CTRL_RECV_OP, 
    CTRL_RECV_LEN, 
    CTRL_RECV_TICKS, 
    CTRL_RECV_DATA, 
    CTRL_RECV_CRC,
} ctrl_recv_state;

/** 
 * 将收到的字节合并为一个packet, 并进行crc校验, 
 * 如果收到完整且正确的packet, 就返回指针; 否则返回NULL  
 **/
ctrl_prot_t *ctrl_recv_char_to_pack(uint8_t ch)
{
    static ctrl_recv_state state = CTRL_RECV_PRE;
    static ctrl_prot_t *now_packet = buf;
    static uint8_t index = 0;
    static uint8_t crc_high, crc_low;
    
    switch (state) {
    case CTRL_RECV_PRE:
        ctrl_crc16_init(crc_high, crc_low);
        now_packet->pre = ch;
        ctrl_crc16_partition(&crc_high, &crc_low, ch);
        state = (ch == CTRLPROT_PRE) ? CTRL_RECV_SRC : CTRL_RECV_PRE;
        break;
    case CTRL_RECV_SRC:
        now_packet->src = ch;
        ctrl_crc16_partition(&crc_high, &crc_low, ch);
        state = (ctrl_recv_check_src(now_packet->src)) ? CTRL_RECV_OP : CTRL_RECV_PRE;
        break;
    case CTRL_RECV_OP:
        now_packet->op = ch;
        ctrl_crc16_partition(&crc_high, &crc_low, ch);
        state = CTRL_RECV_LEN;
        break;
    case CTRL_RECV_LEN:
        now_packet->len = ch;
        ctrl_crc16_partition(&crc_high, &crc_low, ch);
        index = 0;
        state = CTRL_RECV_TICKS;
        break;
    case CTRL_RECV_TICKS:
        ((uint8_t *)(&(now_packet->ticks)))[index++] = ch;
        ctrl_crc16_partition(&crc_high, &crc_low, ch);
        if (index >= 4) {
            index = 0;
            state = (now_packet->len == 0) ? CTRL_RECV_CRC : CTRL_RECV_DATA;
        }
        break;
    case CTRL_RECV_DATA:
        now_packet->data[index++] = ch;
        ctrl_crc16_partition(&crc_high, &crc_low, ch);
        if (index >= now_packet->len) {
            index = 0;
            state = CTRL_RECV_CRC;
        }
        break;
    case CTRL_RECV_CRC:
        ((uint8_t *)(&(now_packet->data)))[now_packet->len + index++] = ch;
        ctrl_crc16_partition(&crc_high, &crc_low, ch);
        if (index >= 2) {
            index = 0;
            state = CTRL_RECV_PRE;
            if (ctrl_crc16_result(crc_high, crc_low) == 0)
                return now_packet;
        }
        break;
    default:
        break;
    }

    return NULL;
}

/** 
 * 为packet添加crc校验 
 **/
int ctrl_send_pack_append_crc(ctrl_prot_t *msg) 
{
    *((uint16_t*)(msg->data + msg->len)) = ctrl_crc16((uint8_t *)msg, msg->len + 8);
    return msg->len + 10;
}